//////////////////////////////////////////////////////////////////////////////////
// Module: z80_bus_decode
// This module decodes Z80 CPU bus signals for I/O operations.
// It detects I/O read/write cycles, extracts the I/O address and data,
// and generates control pulses for peripheral access.
//////////////////////////////////////////////////////////////////////////////////

module z80_bus_decode (
    //--------------------------------------------------------------------------
    // Clock and Reset
    //--------------------------------------------------------------------------
    input  wire             clk,                    // bus clock
    input  wire             rst_n,                  // system reset

    //--------------------------------------------------------------------------
    // Z80 Bus Interface
    //--------------------------------------------------------------------------
    input  wire [15:0]      z80_addr_in,            // Z80 address  (A0–A15)
    input  wire [7:0]       z80_data_in,            // Z80 data
    input  wire             z80_iorq_n_in,          // z80 I/O request
    input  wire             z80_m1_in,              // z80 M1
    input  wire             z80_mreq_n_in,          // z80 memory request
    input  wire             z80_rd_n_in,            // z80 read
    input  wire             z80_wr_n_in,            // z80 write

    //--------------------------------------------------------------------------
    // Decoded Signal
    //--------------------------------------------------------------------------
    output wire [7:0]       z80_dec_addr_out,       // Z80 address to MCU
    output wire [7:0]       z80_dec_data_out,       // Z80 data to MCU
    output wire             z80_dec_rd_out,         // Z80 read operation
    output wire             z80_dec_wr_out,         // Z80 write operation
    output wire             mcu_irq_pulse_out       // Asserted when R/W access is detected
);

// dec output registers
reg [7:0] z80_dec_addr_out_reg;
reg [7:0] z80_dec_data_out_reg;
reg       z80_dec_rd_out_reg;
reg       z80_dec_wr_out_reg;

// Synchronizers for Z80 /RD and /WR control signals
reg [1:0] z80_rd_sync;
reg [1:0] z80_wr_sync;

assign z80_rd_en = ~z80_iorq_n_in & ~z80_rd_n_in & z80_m1_in;   // Z80 /RD enabled
assign z80_wr_en = ~z80_iorq_n_in & ~z80_wr_n_in & z80_m1_in;   // z80 /WR enabled

always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        z80_rd_sync <= 2'b00;
        z80_wr_sync <= 2'b00;
    end
    else begin
        z80_rd_sync <= { z80_rd_sync[0], z80_rd_en };
        z80_wr_sync <= { z80_wr_sync[0], z80_wr_en };
    end
end

assign z80_rd_pulse = z80_rd_sync == 2'b01;                 // Z80 read signal pulse
assign z80_wr_pulse = z80_wr_sync == 2'b01;                 // Z80 write signal pulse

always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        z80_dec_addr_out_reg <= 0;
        z80_dec_data_out_reg <= 0;
        z80_dec_rd_out_reg   <= 0;
        z80_dec_wr_out_reg   <= 0;
    end
    else begin
        if(z80_rd_en) begin
            z80_dec_addr_out_reg <= z80_addr_in[7:0];
            z80_dec_wr_out_reg   <= 1'b0;
            z80_dec_rd_out_reg   <= 1'b1;
        end
        else if(z80_wr_en) begin
            z80_dec_addr_out_reg <= z80_addr_in[7:0];
            z80_dec_data_out_reg <= z80_data_in;                   // Z80 data to MCU
            z80_dec_wr_out_reg   <= 1'b1;
            z80_dec_rd_out_reg   <= 1'b0;
        end
        else begin
            z80_dec_wr_out_reg   <= 1'b0;
            z80_dec_rd_out_reg   <= 1'b0;
        end
    end
end

// Output
assign z80_dec_addr_out  = z80_dec_addr_out_reg;                 // Z80 periphral address to MCU
assign z80_dec_data_out  = z80_dec_data_out_reg;                 // Z80 periphral data to MCU
assign z80_dec_rd_out    = z80_dec_rd_out_reg;                   // Always 1 duration reading (/IORQ=0, /WR=1, /RD=0) 
assign z80_dec_wr_out    = z80_dec_wr_out_reg;                   // Always 1 duration writing (/IORQ=0, /WR=0, /RD=1) 
assign mcu_irq_pulse_out = ~(z80_rd_pulse | z80_wr_pulse);       // MCU irq line (asserted low)

endmodule